/////////////////////////////////////////////////////////////////////////////
// Original code from libhdfs3. Copyright (c) 2013 - 2014, Pivotal Inc.
// All rights reserved. Author: Zhanwei Wang
/////////////////////////////////////////////////////////////////////////////
//  Modifications by Kumo Inc.
// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//



#pragma once

#include <memory>
#include <kmhdfs/server/namenode.h>
#include <kmhdfs/server/namenode_info.h>
#include <kmhdfs/common/thread.h>

namespace Hdfs {
namespace Internal {

class NamenodeProxy: public Namenode {
public:
    NamenodeProxy(const std::vector<NamenodeInfo> & namenodeInfos, const std::string & tokenService,
                  const SessionConfig & c, const RpcAuth & a);
    ~NamenodeProxy();

public:

    void getBlockLocations(const std::string & src, int64_t offset,
                           int64_t length, LocatedBlocks & lbs);

    FileStatus create(const std::string & src, const Permission & masked,
                      const std::string & clientName, int flag, bool createParent,
                      short replication, int64_t blockSize);

    std::pair<std::shared_ptr<LocatedBlock>, std::shared_ptr<FileStatus> > append(
        const std::string& src, const std::string& clientName, const uint32_t& flag);

    bool setReplication(const std::string & src, short replication);

    void setPermission(const std::string & src, const Permission & permission);

    void setOwner(const std::string & src, const std::string & username,
                  const std::string & groupname);

    void abandonBlock(const ExtendedBlock & b, const std::string & src,
                      const std::string & holder, int64_t fileId);

    std::shared_ptr<LocatedBlock> addBlock(const std::string & src,
                                      const std::string & clientName, const ExtendedBlock * previous,
                                      const std::vector<DatanodeInfo> & excludeNodes,
                                      int64_t fileId);

    std::shared_ptr<LocatedBlock> getAdditionalDatanode(const std::string & src,
            const ExtendedBlock & blk,
            const std::vector<DatanodeInfo> & existings,
            const std::vector<std::string> & storageIDs,
            const std::vector<DatanodeInfo> & excludes, int numAdditionalNodes,
            const std::string & clientName);

    bool complete(const std::string & src, const std::string & clientName,
                  const ExtendedBlock * last, int64_t fileId);

    void reportBadBlocks(const std::vector<LocatedBlock> & blocks);

    bool rename(const std::string & src, const std::string & dst);

    void concat(const std::string & trg, const std::vector<std::string> & srcs);

    bool truncate(const std::string & src, int64_t size,
                  const std::string & clientName);

    void getLease(const std::string & src, const std::string & clientName);

    void releaseLease(const std::string & src, const std::string & clientName);

    /*void rename2(const std::string & src, const std::string & dst)
     throw (AccessControlException, DSQuotaExceededException,
     FileAlreadyExistsException, FileNotFoundException,
     NSQuotaExceededException, ParentNotDirectoryException,
     SafeModeException, UnresolvedLinkException, HdfsIOException) ;*/

    bool deleteFile(const std::string & src, bool recursive);

    bool mkdirs(const std::string & src, const Permission & masked,
                bool createParent);

    bool getListing(const std::string & src, const std::string & startAfter,
                    bool needLocation, std::vector<FileStatus> & dl);

    void renewLease(const std::string & clientName);

    bool recoverLease(const std::string & src, const std::string & clientName);

    std::vector<int64_t> getFsStats();

    void metaSave(const std::string & filename);

    FileStatus getFileInfo(const std::string & src);

    FileStatus getFileLinkInfo(const std::string & src);

    void setQuota(const std::string & path, int64_t namespaceQuota,
                  int64_t diskspaceQuota);

    void fsync(const std::string & src, const std::string & client);

    void setTimes(const std::string & src, int64_t mtime, int64_t atime);

    void createSymlink(const std::string & target, const std::string & link,
                       const Permission & dirPerm, bool createParent);

    std::string getLinkTarget(const std::string & path);

    std::shared_ptr<LocatedBlock> updateBlockForPipeline(const ExtendedBlock & block,
            const std::string & clientName);

    void updatePipeline(const std::string & clientName,
                        const ExtendedBlock & oldBlock, const ExtendedBlock & newBlock,
                        const std::vector<DatanodeInfo> & newNodes,
                        const std::vector<std::string> & storageIDs);

    Token getDelegationToken(const std::string & renewer);

    int64_t renewDelegationToken(const Token & token);

    void cancelDelegationToken(const Token & token);

    void close();

private:
    std::shared_ptr<Namenode> getActiveNamenode(uint32_t & oldValue);
    void failoverToNextNamenode(uint32_t oldValue);

private:
    bool enableNamenodeHA;
    int maxNamenodeHARetry;
    mutex mut;
    std::string clusterid;
    std::vector<std::shared_ptr<Namenode> > namenodes;
    uint32_t currentNamenode;
};

}
}
